/*
 * Copyright (c) 2016- 2020 qolome.com Inc. All Rights Reserved. ProjectName: qolome-knowledge FileName: Mask.java
 * Author: jiangfeng@qolome.com Date: 2020/4/5 上午11:23 LastModified: 2020/04/05 11:23:05
 */

package com.qolome.knowledge.net.ip;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import lombok.extern.slf4j.Slf4j;

/**
 * @author Qolome
 * @version V1.0
 * @Description
 * @date 2020年 04月05日 11:23:10
 */
@Slf4j
public class NetUtils {

    // public 1
    // private 2
    // protected 4
    // static 8
    // abstract 1024
    // final 16
    // interface 512
    // native 256
    // strictfp 2048
    // synchronized 32
    // transient 128
    // volatile 64

    public static final String REGEX_IP =
        "(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)";

    public static void main(String[] args) {

        boolean result = isIdenticalSubnetwork("255.255.0.0", "172.16.10.1", "172.16.10.2", "172.16.1.2"

        );
        log.info("这些IP是否同一子网络:{}", result);
    }

    /**
     * @param subnetMask
     *            子网掩码
     * @param ips
     *            IP地址
     * @return 校验结果
     */
    public static Boolean isIdenticalSubnetwork(String subnetMask, String... ips) {

        // IP地址数量校验
        if (ips.length < 2) {
            throw new IllegalArgumentException(" least two ip addresses");
        }

        // 去重,转型
        List<Short[]> ipList = Stream.of(ips).distinct().map(NetUtils::ip2Short).collect(Collectors.toList());

        // 子网掩码
        Short[] mask = ip2Short(subnetMask);

        // 第一个作为基准值
        Short[] reference = compute(ipList.get(0), mask);

        // 循环对比,只要有一个不是就返回
        for (int i = 1; i < ipList.size(); i++) {
            if (!Arrays.equals(reference, compute(ipList.get(i), mask))) {
                return false;
            }
        }

        return true;
    }

    private static Short[] ip2Short(String ip) {

        // IP校验
        if (!Pattern.compile(REGEX_IP).matcher(ip).matches()) {
            throw new IllegalArgumentException(String.format("ip address parameter error: %s", ip));
        }

        // 返回short类型数组 IP
        return Stream.of(ip.split("\\.")).map(Short::valueOf).toArray(Short[]::new);

    }

    // IP 与子网掩码 & 运算
    private static Short[] compute(Short[] subnetMask, Short[] ip) {
        return new Short[] {(short)(subnetMask[0] & ip[0]), (short)(subnetMask[1] & ip[1]),
            (short)(subnetMask[2] & ip[2]), (short)(subnetMask[3] & ip[3])};
    }

}
